﻿using DataTransfer.Core.Models;
using DataTransfer.Core.Providers;
using DataTransfer.SDK;
using DataTransfer.SDK.Events;
using DataTransfer.SDK.Models;
using MiniFox;
using MiniFox.Caching;
using MiniFox.Components;
using MiniFox.Infrastructure;
using MiniFox.Platform.Applications.Auth;
using MiniFox.Platform.File.Models;

namespace DataTransfer.Core.Services
{
    /// <summary>
    /// 
    /// </summary>
    [AutoRegister]
    public abstract class ImportEngine : Component, IImportEventListener
    {
        IImporter _importer;
        public event EventHandler<ImporterBeforeWriteEventArgs> BeforeWrite;
        public event EventHandler<ImporterAfterWriteEventArgs> AfterWrite;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="importerName"></param>
        /// <param name="authStateManagement"></param>
        public ImportEngine(string importerName, IAuthStateManagement authStateManagement)
        {
            ImporterName = importerName;
            AuthStateManagement = authStateManagement;
        }

        protected IAuthStateManagement AuthStateManagement { get; }
        /// <summary>
        /// 
        /// </summary>
        public string ImporterName
        {
            get;
        }
        /// <summary>
        /// 
        /// </summary>
        [AutoWired]
        protected virtual IImportConfigProvider Configuration
        {
            get;
            set;
        }
        /// <summary>
        /// 
        /// </summary>
        protected internal IImporter Importer
        {
            get
            {
                if (_importer == null)
                {
                    _importer = Configuration.GetImporter(ImporterName);
                }
                return _importer;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        protected virtual DataWriter CreateDataWriter()
        {
            var type = Importer.DataWriterType;
            var instance = Activator.CreateInstance(type, Importer, AuthStateManagement);
            var writer = instance as DataWriter;
            return writer;
        }
        DataWriter _dataWriter;
        /// <summary>
        /// 
        /// </summary>
        public DataWriter DataWriter
        {
            get
            {
                if (_dataWriter == null)
                    _dataWriter = CreateDataWriter();
                return _dataWriter;
            }
        }

        #region 缓存
        /// <summary>
        /// 
        /// </summary>
        protected virtual CacheProvider Cache
        {
            get
            {
                return CacheService.GetCacheProvider(Name);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="batch"></param>
        protected virtual void SetCache(ImportBatch batch)
        {
            this.Cache.Add(batch.BatchId, batch);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="batchId"></param>
        /// <returns></returns>
        protected virtual ImportBatch GetCache(string batchId)
        {
            var batch = this.Cache.Get<ImportBatch>(batchId);
            return batch;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="importBatch"></param>
        protected virtual void ResetCache(ImportBatch importBatch)
        {
            string batchId = importBatch.BatchId;
            this.Cache.Remove(batchId);
        }

        #endregion

        #region 预加载相关
        /// <summary>
        /// 
        /// </summary>
        /// <param name="fileDatas"></param>
        /// <returns></returns>
        public ImportBatch Preload(FileData[] fileDatas)
        {
            ImportBatch batch = new();
            var batchId = SequenceGUID.NewGUID();
            batch.BatchId = batchId;
            foreach (var fileData in fileDatas)
            {
                var group = PreloadGroup(fileData);
                batch.Groups.Add(group);
            }

            SetCache(batch);
            return batch;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="fileData"></param>
        /// <returns></returns>
        protected abstract ImportGroup PreloadGroup(FileData fileData);

        #endregion

        #region 预览相关


        public object Preview(PagedQueryObject<PreviewRequest> request)
        {
            var batch = GetCache(request.Parameters.BatchId);
            var group = batch.Groups.SingleOrDefault(g => g.File.FileId == request.Parameters.FileId);
            return PreviewData(group, request);
        }
        protected abstract object PreviewData(ImportGroup group, PagedQueryObject<PreviewRequest> request);

        public void UndoAll(UndoAllRequest request)
        {
            var batch = GetCache(request.BatchId);
            var group = batch.Groups.SingleOrDefault(g => g.File.FileId == request.FileId);
            UndoAllData(group, request);
        }
        protected abstract void UndoAllData(ImportGroup group, UndoAllRequest request);

        public object Undo(UndoRequest request)
        {
            var batch = GetCache(request.BatchId);
            var group = batch.Groups.SingleOrDefault(g => g.File.FileId == request.FileId);
            return UndoData(group, request);
        }
        protected abstract object UndoData(ImportGroup group, UndoRequest request);

        public object Remove(RemoveRequest request)
        {
            var batch = GetCache(request.BatchId);
            var group = batch.Groups.SingleOrDefault(g => g.File.FileId == request.FileId);
            return RemoveData(group, request);
        }
        protected abstract object RemoveData(ImportGroup group, RemoveRequest request);

        public object Update(UpdateRequest request)
        {
            var batch = GetCache(request.BatchId);
            var group = batch.Groups.SingleOrDefault(g => g.File.FileId == request.FileId);
            return UpdateData(group, request);
        }
        protected abstract object UpdateData(ImportGroup group, UpdateRequest request);

        #endregion

        #region 确认导入

        public ImportBatchResult Accept(ImportAcceptance request)
        {
            string batchId = request.BatchId;
            var importBatch = Cache.Get<ImportBatch>(batchId);
            if (importBatch == null)
                return null;

            return Execute(importBatch);
        }

        protected virtual ImportBatchResult Execute(ImportBatch importBatch)
        {
            var result = new ImportBatchResult 
            { 
                BatchId = importBatch.BatchId                
            };
            importBatch.Groups.ForEach(group =>
            {
                var groupResult = CreateGroupResult(group);
                result.GroupResults.Add(groupResult);
            });
            ResetCache(importBatch);
            return result;
        }

        protected virtual ImportGroupResult CreateGroupResult(ImportGroup group)
        {
            var result = new ImportGroupResult
            {
                File = group.File
            };
            OnBeforeWrite(new ImporterBeforeWriteEventArgs(Importer, group.OriginalData));
            result.ImportSummary = DataWriter.ExecuteWrite(group.OriginalData);
            OnAfterWrite(new ImporterAfterWriteEventArgs(Importer, group.OriginalData, result.ImportSummary));
            return result;
        }

        #endregion

        #region 直接导入
        /// <summary>
        /// 
        /// </summary>
        /// <param name="fileDatas"></param>
        /// <returns></returns>
        public ImportBatchResult Execute(FileData[] fileDatas)
        {
            var batch = Preload(fileDatas);
            if (Importer.PreImport)
            {
                var result = new ImportBatchResult
                {
                    BatchId = batch.BatchId,
                    GroupResults = (from @group in batch.Groups
                                    select new ImportGroupResult
                                    {
                                        File = @group.File,
                                        ImportSummary = @group.OriginalSummary
                                    }).ToList()
                };
                return result;
            }
            return Execute(batch);
        }
        #endregion

        #region event
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnBeforeWrite(ImporterBeforeWriteEventArgs e)
        {
            BeforeWrite?.Invoke(this, e);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnAfterWrite(ImporterAfterWriteEventArgs e)
        {
            AfterWrite?.Invoke(this, e);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        protected internal abstract FileData GetTemplate();

        public virtual FileData GetFile(string batchId, string fileId)
        {
            var batch = GetCache(batchId);
            var group = batch.Groups.SingleOrDefault(g => g.File.FileId == fileId);
            return group.File;
        }

        #endregion
    }

}
